package server

import (
	"context"
	"fmt"
	tech "gitee.com/min65535/gotechback/api/v1/tech/pb"
	"gitee.com/min65535/gotechback/techback/conf"
	"gitee.com/min65535/gotechback/techback/service"
	"gitee.com/min65535/gotechback/techback/util"
	"gitee.com/min65535/gotechback/techback/util/json"
	"github.com/gin-gonic/gin"
	"github.com/go-kratos/kratos/v2/middleware/metrics"
	"github.com/go-kratos/kratos/v2/middleware/recovery"
	"github.com/go-kratos/kratos/v2/middleware/tracing"
	"github.com/go-kratos/kratos/v2/middleware/validate"
	"github.com/go-kratos/kratos/v2/transport/http"
	"github.com/sirupsen/logrus"
	log "github.com/sirupsen/logrus"
	"github.com/thinkerou/favicon"
	httpGo "net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// NewHTTPServer 新建http server.
func NewHTTPServer(c *conf.Config, svc *service.BaseService) *http.Server {
	log.Infof("NewHTTPServer#cfg: %s", json.StringifyJson(c))
	var opts = []http.ServerOption{
		http.Middleware(
			// Auth(svc.AuthTokenInside, "/api/v1/tech"), //  认证
			// Auth(svc, "/api/v1/tech"), //  认证
			recovery.Recovery(),
			tracing.Server(),
			metrics.Server(),
			validate.Validator(),
		),
	}
	if c.Server.HTTP.Network != "" {
		opts = append(opts, http.Network(c.Server.HTTP.Network))
	}
	if c.Server.HTTP.Addr != "" {
		opts = append(opts, http.Address(c.Server.HTTP.Addr))
	}
	if c.Server.HTTP.Timeout != 0 {
		opts = append(opts, http.Timeout(time.Duration(c.Server.HTTP.Timeout)*time.Millisecond))
	}
	// switch util.GetRunEnv() {
	// case "prod", "preprod":
	// 	opts = append(opts, http.RequestDecoder(
	// 		enc.DecryptRequestBody(),
	// 	))
	// }
	// 自定义request编码
	// opts = append(opts, http.RequestDecoder(MyProtoRequestDecoder))
	// 自定义response编码
	// opts = append(opts, http.ResponseEncoder(MyProtoResponseEncoder))
	opts = append(opts, http.ResponseEncoder(MyResponseEncoder))
	// 自定义error编码
	opts = append(opts, http.ErrorEncoder(MyErrorEncoder))
	srv := http.NewServer(opts...)
	// 在server调用RegisterUserHTTPServer，可以直接把实现user_http.pb.go中UserHTTPServer接口的 service注册到http服务器中
	tech.RegisterEmailEventHTTPServer(srv, svc)
	go newHttpServerInnerSub(svc)

	return srv
}

// 启动另一个服务(暂不使用)
// While parsing a protocol message, the input ended unexpectedly in the middle of a field.
// This could mean either that the input has been truncated or that an embedded message misreported its own length.
func newHttpServerInnerSub(svc *service.BaseService) {
	eg := gin.Default()
	root, _ := util.BinaryPathGet()
	eg.Use(favicon.New(root + "static/favicon.ico"))
	eg.Static("/static", root+"/static")
	eg.Handle("GET", "/", func(c *gin.Context) {
		c.Header("Access-Control-Allow-Origin", "*")
		// c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
		c.Header("Access-Control-Allow-Methods", "GET")
		yfLogin(c, svc)
	})

	run("3001", eg)
}

// 启动服务
func run(port string, engine httpGo.Handler) {
	httpSrv := &httpGo.Server{Addr: fmt.Sprintf(":%s", port), Handler: engine}
	go func() {
		err := httpSrv.ListenAndServe()
		if err != nil && err != httpGo.ErrServerClosed {
			panic(err)
		}
	}()
	// init signal
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
	for {
		s := <-c
		switch s {
		case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
			ginStop(httpSrv)
			return
		default:
			return
		}
	}

}

// gin gracefully stop server
func ginStop(httpSrv *httpGo.Server) {
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()
	if err := httpSrv.Shutdown(ctx); err != nil {
		time.Sleep(time.Second)
		return
	}
}

func getReLoginURL() string {
	ur := ``
	switch util.GetRunEnv() {
	case "test", "":
		ur = `http://127.0.0.1:80`
	case "prod":
		ur = `http://127.0.0.1:80`
	}
	return ur
}

func getRedirectURL() string {
	ur := ``
	switch util.GetRunEnv() {
	case "test", "":
		ur = `http://127.0.0.1:80/index.html`
	case "prod":
		ur = `http://127.0.0.1:80/index.html`
	}
	return ur
}

func yfLogin(c *gin.Context, svc *service.BaseService) {
	ticket := c.Query("ticket")
	cx := c.Request.Context()
	uid, user, token, err := svc.AuthTokenThird(cx, ticket)
	if err != nil {
		logrus.Errorf("login failed, ticket:%v, err:%v", ticket, err)
		c.Redirect(302, getReLoginURL())
		return
	}

	c.SetCookie("userid", fmt.Sprintf("%d", uid), 86400, "/", "", false, false)
	c.SetCookie("username", user, 86400, "/", "", false, false)
	c.SetCookie("token", token, 86400, "/", "", false, false)
	c.Redirect(302, getRedirectURL())
}
